home *** CD-ROM | disk | FTP | other *** search
- # $Id: LibXSLT.pm 228 2009-10-07 12:25:23Z pajas $
- #
- # This is free software, you may use it and distribute it under the same terms as
- # Perl itself.
- #
- # Copyright 2001-2009 AxKit.com Ltd.
- #
- #
- package XML::LibXSLT;
-
- use strict;
- use vars qw($VERSION @ISA $USE_LIBXML_DATA_TYPES $MatchCB $ReadCB $OpenCB $CloseCB);
-
- sub REQUIRE_XML_LIBXML_ABI_VERSION { 2 }
-
- use XML::LibXML 1.70;
- use XML::LibXML::Literal;
- use XML::LibXML::Boolean;
- use XML::LibXML::Number;
- use XML::LibXML::NodeList;
-
-
- BEGIN {
- use Carp;
-
- require Exporter;
-
- $VERSION = "1.70";
-
- require DynaLoader;
-
- @ISA = qw(DynaLoader);
-
- # avoid possible shared library name conflict on Win32
- # not using this trick on 5.10.0 (suffering from DynaLoader bug)
- local $DynaLoader::dl_dlext = "xs.$DynaLoader::dl_dlext" if (($^O eq 'MSWin32') && ($] ne '5.010000'));
-
- bootstrap XML::LibXSLT $VERSION;
-
- # the following magic lets XML::LibXSLT internals know
- # where to register XML::LibXML proxy nodes
- INIT_THREAD_SUPPORT() if XML::LibXML::threads_shared_enabled();
- $USE_LIBXML_DATA_TYPES = 0;
- }
-
-
- sub new {
- my $class = shift;
- my %options = @_;
- my $self = bless \%options, $class;
- return $self;
- }
-
- # ido - perl dispatcher
- sub perl_dispatcher {
- my $func = shift;
- my @params = @_;
- my @perlParams;
-
- my $i = 0;
- while (@params) {
- my $type = shift(@params);
- if ($type eq 'XML::LibXML::Literal' or
- $type eq 'XML::LibXML::Number' or
- $type eq 'XML::LibXML::Boolean')
- {
- my $val = shift(@params);
- unshift(@perlParams, $USE_LIBXML_DATA_TYPES ? $type->new($val) : $val);
- }
- elsif ($type eq 'XML::LibXML::NodeList') {
- my $node_count = shift(@params);
- my @nodes = splice(@params, 0, $node_count);
- # warn($_->getName) for @nodes;
- unshift(@perlParams, $type->new(@nodes));
- }
- }
-
- $func = "main::$func" unless ref($func) || $func =~ /(.+)::/;
- no strict 'refs';
- my $res = $func->(@perlParams);
- return $res;
- }
-
-
- sub xpath_to_string {
- my @results;
- while (@_) {
- my $value = shift(@_); $value = '' unless defined $value;
- push @results, $value;
- if (@results % 2) {
- # key
- $results[-1] =~ s/:/_/g; # XSLT doesn't like names with colons
- }
- else {
- if ($value =~ s/'/', "'", '/g) {
- $results[-1] = "concat('$value')";
- }
- else {
- $results[-1] = "'$results[-1]'";
- }
- }
- }
- return @results;
- }
-
- #-------------------------------------------------------------------------#
- # callback functions #
- #-------------------------------------------------------------------------#
-
- sub security_callbacks {
- my $self = shift;
- my $scbclass = shift;
-
- if ( defined $scbclass ) {
- $self->{XML_LIBXSLT_SECPREFS} = $scbclass;
- }
- return $self->{XML_LIBXSLT_SECPREFS};
- }
-
- sub input_callbacks {
- my $self = shift;
- my $icbclass = shift;
-
- if ( defined $icbclass ) {
- $self->{XML_LIBXSLT_CALLBACK_STACK} = $icbclass;
- }
- return $self->{XML_LIBXSLT_CALLBACK_STACK};
- }
-
- sub match_callback {
- my $self = shift;
- if ( ref $self ) {
- if ( scalar @_ ) {
- $self->{XML_LIBXSLT_MATCH_CB} = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- return $self->{XML_LIBXSLT_MATCH_CB};
- }
- else {
- $MatchCB = shift if scalar @_;
- return $MatchCB;
- }
- }
-
- sub read_callback {
- my $self = shift;
- if ( ref $self ) {
- if ( scalar @_ ) {
- $self->{XML_LIBXSLT_READ_CB} = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- return $self->{XML_LIBXSLT_READ_CB};
- }
- else {
- $ReadCB = shift if scalar @_;
- return $ReadCB;
- }
- }
-
- sub close_callback {
- my $self = shift;
- if ( ref $self ) {
- if ( scalar @_ ) {
- $self->{XML_LIBXSLT_CLOSE_CB} = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- return $self->{XML_LIBXSLT_CLOSE_CB};
- }
- else {
- $CloseCB = shift if scalar @_;
- return $CloseCB;
- }
- }
-
- sub open_callback {
- my $self = shift;
- if ( ref $self ) {
- if ( scalar @_ ) {
- $self->{XML_LIBXSLT_OPEN_CB} = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- return $self->{XML_LIBXSLT_OPEN_CB};
- }
- else {
- $OpenCB = shift if scalar @_;
- return $OpenCB;
- }
- }
-
- sub callbacks {
- my $self = shift;
- if ( ref $self ) {
- if (@_) {
- my ($match, $open, $read, $close) = @_;
- @{$self}{qw(XML_LIBXSLT_MATCH_CB XML_LIBXSLT_OPEN_CB XML_LIBXSLT_READ_CB XML_LIBXSLT_CLOSE_CB)} = ($match, $open, $read, $close);
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- else {
- return @{$self}{qw(XML_LIBXSLT_MATCH_CB XML_LIBXSLT_OPEN_CB XML_LIBXSLT_READ_CB XML_LIBXSLT_CLOSE_CB)};
- }
- }
- else {
- if (@_) {
- ( $MatchCB, $OpenCB, $ReadCB, $CloseCB ) = @_;
- }
- else {
- return ( $MatchCB, $OpenCB, $ReadCB, $CloseCB );
- }
- }
- }
-
- sub _init_callbacks{
- my $self = shift;
- my $icb = $self->{XML_LIBXSLT_CALLBACK_STACK};
-
- unless ( defined $icb ) {
- $self->{XML_LIBXSLT_CALLBACK_STACK} = XML::LibXML::InputCallback->new();
- $icb = $self->{XML_LIBXSLT_CALLBACK_STACK};
- }
-
- my $mcb = $self->match_callback();
- my $ocb = $self->open_callback();
- my $rcb = $self->read_callback();
- my $ccb = $self->close_callback();
-
- if ( defined $mcb and defined $ocb and defined $rcb and defined $ccb ) {
- $icb->register_callbacks( [$mcb, $ocb, $rcb, $ccb] );
- }
-
- $self->lib_init_callbacks();
- $icb->init_callbacks();
- }
-
- sub _cleanup_callbacks {
- my $self = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK}->cleanup_callbacks();
- my $mcb = $self->match_callback();
- if ( defined $mcb ) {
- $self->{XML_LIBXSLT_CALLBACK_STACK}->unregister_callbacks( [$mcb] );
- }
- }
-
- sub parse_stylesheet {
- my $self = shift;
-
- $self->_init_callbacks();
-
- my $stylesheet;
- eval { $stylesheet = $self->_parse_stylesheet(@_); };
-
- $self->_cleanup_callbacks();
-
- my $err = $@;
- if ($err) {
- croak $err;
- }
-
- my $rv = {
- XML_LIBXSLT_STYLESHEET => $stylesheet,
- XML_LIBXSLT_CALLBACK_STACK => $self->{XML_LIBXSLT_CALLBACK_STACK},
- XML_LIBXSLT_MATCH_CB => $self->{XML_LIBXSLT_MATCH_CB},
- XML_LIBXSLT_OPEN_CB => $self->{XML_LIBXSLT_OPEN_CB},
- XML_LIBXSLT_READ_CB => $self->{XML_LIBXSLT_READ_CB},
- XML_LIBXSLT_CLOSE_CB => $self->{XML_LIBXSLT_CLOSE_CB},
- XML_LIBXSLT_SECPREFS => $self->{XML_LIBXSLT_SECPREFS},
- };
-
- return bless $rv, "XML::LibXSLT::StylesheetWrapper";
- }
-
- sub parse_stylesheet_file {
- my $self = shift;
-
- $self->_init_callbacks();
-
- my $stylesheet;
- eval { $stylesheet = $self->_parse_stylesheet_file(@_); };
-
- $self->_cleanup_callbacks();
-
- my $err = $@;
- if ($err) {
- croak $err;
- }
-
- my $rv = {
- XML_LIBXSLT_STYLESHEET => $stylesheet,
- XML_LIBXSLT_CALLBACK_STACK => $self->{XML_LIBXSLT_CALLBACK_STACK},
- XML_LIBXSLT_MATCH_CB => $self->{XML_LIBXSLT_MATCH_CB},
- XML_LIBXSLT_OPEN_CB => $self->{XML_LIBXSLT_OPEN_CB},
- XML_LIBXSLT_READ_CB => $self->{XML_LIBXSLT_READ_CB},
- XML_LIBXSLT_CLOSE_CB => $self->{XML_LIBXSLT_CLOSE_CB},
- XML_LIBXSLT_SECPREFS => $self->{XML_LIBXSLT_SECPREFS},
- };
-
- return bless $rv, "XML::LibXSLT::StylesheetWrapper";
- }
-
- sub register_xslt_module {
- my $self = shift;
- my $module = shift;
- # Not implemented
- }
-
- 1;
-
- package XML::LibXSLT::StylesheetWrapper;
-
- use strict;
- use vars qw($MatchCB $ReadCB $OpenCB $CloseCB);
-
- use XML::LibXML;
- use Carp;
-
- sub security_callbacks {
- my $self = shift;
- my $scbclass = shift;
-
- if ( defined $scbclass ) {
- $self->{XML_LIBXSLT_SECPREFS} = $scbclass;
- }
- return $self->{XML_LIBXSLT_SECPREFS};
- }
-
- sub input_callbacks {
- my $self = shift;
- my $icbclass = shift;
-
- if ( defined $icbclass ) {
- $self->{XML_LIBXSLT_CALLBACK_STACK} = $icbclass;
- }
- return $self->{XML_LIBXSLT_CALLBACK_STACK};
- }
-
- sub match_callback {
- my $self = shift;
- if ( ref $self ) {
- if ( scalar @_ ) {
- $self->{XML_LIBXSLT_MATCH_CB} = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- return $self->{XML_LIBXSLT_MATCH_CB};
- }
- else {
- $MatchCB = shift if scalar @_;
- return $MatchCB;
- }
- }
-
- sub read_callback {
- my $self = shift;
- if ( ref $self ) {
- if ( scalar @_ ) {
- $self->{XML_LIBXSLT_READ_CB} = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- return $self->{XML_LIBXSLT_READ_CB};
- }
- else {
- $ReadCB = shift if scalar @_;
- return $ReadCB;
- }
- }
-
- sub close_callback {
- my $self = shift;
- if ( ref $self ) {
- if ( scalar @_ ) {
- $self->{XML_LIBXSLT_CLOSE_CB} = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- return $self->{XML_LIBXSLT_CLOSE_CB};
- }
- else {
- $CloseCB = shift if scalar @_;
- return $CloseCB;
- }
- }
-
- sub open_callback {
- my $self = shift;
- if ( ref $self ) {
- if ( scalar @_ ) {
- $self->{XML_LIBXSLT_OPEN_CB} = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- return $self->{XML_LIBXSLT_OPEN_CB};
- }
- else {
- $OpenCB = shift if scalar @_;
- return $OpenCB;
- }
- }
-
- sub callbacks {
- my $self = shift;
- if ( ref $self ) {
- if (@_) {
- my ($match, $open, $read, $close) = @_;
- @{$self}{qw(XML_LIBXSLT_MATCH_CB XML_LIBXSLT_OPEN_CB XML_LIBXSLT_READ_CB XML_LIBXSLT_CLOSE_CB)} = ($match, $open, $read, $close);
- $self->{XML_LIBXSLT_CALLBACK_STACK} = undef;
- }
- else {
- return @{$self}{qw(XML_LIBXSLT_MATCH_CB XML_LIBXSLT_OPEN_CB XML_LIBXSLT_READ_CB XML_LIBXSLT_CLOSE_CB)};
- }
- }
- else {
- if (@_) {
- ( $MatchCB, $OpenCB, $ReadCB, $CloseCB ) = @_;
- }
- else {
- return ( $MatchCB, $OpenCB, $ReadCB, $CloseCB );
- }
- }
- }
-
- sub _init_callbacks {
- my $self = shift;
- my $icb = $self->{XML_LIBXSLT_CALLBACK_STACK};
-
- unless ( defined $icb ) {
- $self->{XML_LIBXSLT_CALLBACK_STACK} = XML::LibXML::InputCallback->new();
- $icb = $self->{XML_LIBXSLT_CALLBACK_STACK};
- }
-
- my $mcb = $self->match_callback();
- my $ocb = $self->open_callback();
- my $rcb = $self->read_callback();
- my $ccb = $self->close_callback();
-
- if ( defined $mcb and defined $ocb and defined $rcb and defined $ccb ) {
- $icb->register_callbacks( [$mcb, $ocb, $rcb, $ccb] );
- }
- $self->XML::LibXSLT::lib_init_callbacks();
- $icb->init_callbacks();
-
- my $scb = $self->{XML_LIBXSLT_SECPREFS};
- if ( $scb ) {
- $scb->init_callbacks();
- }
- }
-
- sub _cleanup_callbacks {
- my $self = shift;
- $self->{XML_LIBXSLT_CALLBACK_STACK}->cleanup_callbacks();
- my $mcb = $self->match_callback();
- if ( defined $mcb ) {
- $self->{XML_LIBXSLT_CALLBACK_STACK}->unregister_callbacks( [$mcb] );
- }
-
- my $scb = $self->{XML_LIBXSLT_SECPREFS};
- if ( $scb ) {
- $scb->cleanup_callbacks();
- }
- }
-
- sub transform {
- my $self = shift;
- my $doc;
-
- $self->_init_callbacks();
- eval { $doc = $self->{XML_LIBXSLT_STYLESHEET}->transform($self,@_); };
- $self->_cleanup_callbacks();
-
- my $err = $@;
- if ($err) {
- croak $err;
- }
-
- return $doc;
- }
-
- sub transform_file {
- my $self = shift;
- my $doc;
-
- $self->_init_callbacks();
- eval { $doc = $self->{XML_LIBXSLT_STYLESHEET}->transform_file($self,@_); };
- $self->_cleanup_callbacks();
-
- my $err = $@;
- if ($err) {
- croak $err;
- }
-
- return $doc;
- }
-
- sub output_string { shift->{XML_LIBXSLT_STYLESHEET}->_output_string($_[0],0) }
- sub output_as_bytes { shift->{XML_LIBXSLT_STYLESHEET}->_output_string($_[0],1) }
- sub output_as_chars { shift->{XML_LIBXSLT_STYLESHEET}->_output_string($_[0],2) }
- sub output_fh { shift->{XML_LIBXSLT_STYLESHEET}->output_fh(@_) }
- sub output_file { shift->{XML_LIBXSLT_STYLESHEET}->output_file(@_) }
- sub media_type { shift->{XML_LIBXSLT_STYLESHEET}->media_type(@_) }
- sub output_encoding { shift->{XML_LIBXSLT_STYLESHEET}->output_encoding(@_) }
-
- 1;
-
- # XML::LibXSLT::Security Interface #
- #-------------------------------------------------------------------------#
- package XML::LibXSLT::Security;
-
- use strict;
- use Carp;
-
- use vars qw(%OPTION_MAP %_GLOBAL_CALLBACKS);
-
- # Maps the option names used in the perl interface to the numeric values
- # used by libxslt.
- my %OPTION_MAP = (
- read_file => 1,
- write_file => 2,
- create_dir => 3,
- read_net => 4,
- write_net => 5,
- );
-
- %_GLOBAL_CALLBACKS = ();
-
-
- #-------------------------------------------------------------------------#
- # global callback #
- #-------------------------------------------------------------------------#
- sub _security_check {
- my $option = shift;
- my $retval = 1;
-
- if ($option == 3) {
- $retval = 0; # Default create_dir to no access
- }
-
- if (exists $_GLOBAL_CALLBACKS{$option}) {
- $retval = $_GLOBAL_CALLBACKS{$option}->(@_);
- }
-
- return $retval;
- }
-
- #-------------------------------------------------------------------------#
- # member functions and methods #
- #-------------------------------------------------------------------------#
-
- sub new {
- my $class = shift;
- return bless {'_CALLBACKS' => {}}, $class;
- }
-
- # Add a callback for the given security option (read_file, write_file,
- # create_dir, read_net, write_net).
- #
- # To register a callback that handle network read requests:
- # $scb->register_callback( read_net => \&callback );
- sub register_callback {
- my $self = shift;
- my $option = shift;
- my $callback = shift;
-
- unless ( exists $OPTION_MAP{$option} ) {
- croak "Invalid security option '$option'. Must be one of: " .
- join(', ', keys %OPTION_MAP) . ".";
- }
-
- if ( ref $callback eq 'CODE' ) {
- $self->{_CALLBACKS}{ $OPTION_MAP{$option} } = $callback;
- }
- else {
- croak "Invalid argument. The callback must be a reference to a subroutine";
- }
- }
-
- # Removes the callback for the given security option. Causes the given option
- # to use the default security handler (which always allows the action).
- sub unregister_callback {
- my $self = shift;
- my $option = shift;
-
- unless ( exists $OPTION_MAP{$option} ) {
- croak "Invalid security option '$option'. Must be one of: " .
- join(', ', keys %OPTION_MAP) . ".";
- }
-
- delete $self->{_CALLBACKS}{ $OPTION_MAP{$option} };
- }
-
-
- # make it so libxslt can use the callbacks
- sub init_callbacks {
- my $self = shift;
-
- %_GLOBAL_CALLBACKS = %{ $self->{_CALLBACKS} };
- }
-
- # reset libxslt callbacks
- sub cleanup_callbacks {
- my $self = shift;
-
- %_GLOBAL_CALLBACKS = ();
- }
-
- 1;
-
- __END__
-
- =head1 NAME
-
- XML::LibXSLT - Interface to the gnome libxslt library
-
- =head1 SYNOPSIS
-
- use XML::LibXSLT;
- use XML::LibXML;
-
- my $xslt = XML::LibXSLT->new();
-
- my $source = XML::LibXML->load_xml(location => 'foo.xml');
- my $style_doc = XML::LibXML->load_xml(location=>'bar.xsl', no_cdata=>1);
-
- my $stylesheet = $xslt->parse_stylesheet($style_doc);
-
- my $results = $stylesheet->transform($source);
-
- print $stylesheet->output_as_bytes($results);
-
- =head1 DESCRIPTION
-
- This module is an interface to the gnome project's libxslt. This is an
- extremely good XSLT engine, highly compliant and also very fast. I have
- tests showing this to be more than twice as fast as Sablotron.
-
- =head1 OPTIONS
-
- XML::LibXSLT has some global options. Note that these are probably not
- thread or even fork safe - so only set them once per process. Each one
- of these options can be called either as class methods, or as instance
- methods. However either way you call them, it still sets global options.
-
- Each of the option methods returns its previous value, and can be called
- without a parameter to retrieve the current value.
-
- =over
-
- =item max_depth
-
- XML::LibXSLT->max_depth(1000);
-
- This option sets the maximum recursion depth for a stylesheet. See the
- very end of section 5.4 of the XSLT specification for more details on
- recursion and detecting it. If your stylesheet or XML file requires
- seriously deep recursion, this is the way to set it. Default value is
- 250.
-
- =item debug_callback
-
- XML::LibXSLT->debug_callback($subref);
-
- Sets a callback to be used for debug messages. If you don't set this,
- debug messages will be ignored.
-
- =item register_function
-
- XML::LibXSLT->register_function($uri, $name, $subref);
-
- Registers an XSLT extension function mapped to the given URI. For example:
-
- XML::LibXSLT->register_function("urn:foo", "bar",
- sub { scalar localtime });
-
- Will register a C<bar> function in the C<urn:foo> namespace (which you
- have to define in your XSLT using C<xmlns:...>) that will return the
- current date and time as a string:
-
- <xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:foo="urn:foo">
- <xsl:template match="/">
- The time is: <xsl:value-of select="foo:bar()"/>
- </xsl:template>
- </xsl:stylesheet>
-
- Parameters can be in whatever format you like. If you pass in a nodelist
- it will be a XML::LibXML::NodeList object in your perl code, but ordinary
- values (strings, numbers and booleans) will be ordinary perl scalars. If
- you wish them to be C<XML::LibXML::Literal>, C<XML::LibXML::Number> and
- C<XML::LibXML::Number> values respectively then set the variable
- C<$XML::LibXSLT::USE_LIBXML_DATA_TYPES> to a true value. Return values can
- be a nodelist or a plain value - the code will just do the right thing.
- But only a single return value is supported (a list is not converted to
- a nodelist).
-
- =back
-
- =head1 API
-
- The following methods are available on the new XML::LibXSLT object:
-
- =over
-
- =item parse_stylesheet($stylesheet_doc)
-
- C<$stylesheet_doc> here is an XML::LibXML::Document object (see L<XML::LibXML>)
- representing an XSLT file. This method will return a
- XML::LibXSLT::Stylesheet object, or undef on failure. If the XSLT is
- invalid, an exception will be thrown, so wrap the call to
- parse_stylesheet in an eval{} block to trap this.
-
- IMPORTANT: C<$stylesheet_doc> should not contain CDATA sections,
- otherwise libxslt may misbehave. The best way to assure this is to
- load the stylesheet with no_cdata flag, e.g.
-
- my $stylesheet_doc = XML::LibXML->load_xml(location=>"some.xsl", no_cdata=>1);
-
- =item parse_stylesheet_file($filename)
-
- Exactly the same as the above, but parses the given filename directly.
-
- =back
-
- =head1 Input Callbacks
-
- To define XML::LibXSLT or XML::LibXSLT::Stylesheet specific input
- callbacks, reuse the XML::LibXML input callback API as described in
- L<XML::LibXML::InputCallback(3)>.
-
- =head1 Security Callbacks
-
- To create security preferences for the transformation see
- L<XML::LibXSLT::Security>. Once the security preferences have been defined you
- can apply them to an XML::LibXSLT or XML::LibXSLT::Stylesheet instance using
- the C<security_callbacks()> method.
-
- =head1 XML::LibXSLT::Stylesheet
-
- The main API is on the stylesheet, though it is fairly minimal.
-
- One of the main advantages of XML::LibXSLT is that you have a generic
- stylesheet object which you call the transform() method passing in a
- document to transform. This allows you to have multiple transformations
- happen with one stylesheet without requiring a reparse.
-
- =over
-
- =item transform(doc, %params)
-
- my $results = $stylesheet->transform($doc, foo => "value);
- print $stylesheet->output_as_bytes($results);
-
- Transforms the passed in XML::LibXML::Document object, and returns a
- new XML::LibXML::Document. Extra hash entries are used as parameters.
- See output_string
-
- =item transform_file(filename, %params)
-
- my $results = $stylesheet->transform_file($filename, bar => "value");
-
- =item output_as_bytes(result)
-
- Returns a scalar that is the XSLT rendering of the
- XML::LibXML::Document object using the desired output format
- (specified in the xsl:output tag in the stylesheet). Note that you can
- also call $result->toString, but that will *always* output the
- document in XML format which may not be what you asked for in the
- xsl:output tag. The scalar is a byte string encoded in the output
- encoding specified in the stylesheet.
-
- =item output_as_chars(result)
-
- Like C<output_as_bytes(result)>, but always return the output as (UTF-8
- encoded) string of characters.
-
- =item output_string(result)
-
- DEPRECATED: This method is something between
- C<output_as_bytes(result)> and C<output_as_bytes(result)>: The scalar
- returned by this function appears to Perl as characters (UTF8 flag is
- on) if the output encoding specified in the XSLT stylesheet was UTF-8
- and as bytes if no output encoding was specified or if the output
- encoding was other than UTF-8. Since the behavior of this function
- depends on the particular stylesheet, it is deprecated in favor of
- C<output_as_bytes(result)> and C<output_as_chars(result)>.
-
- =item output_fh(result, fh)
-
- Outputs the result to the filehandle given in C<$fh>.
-
- =item output_file(result, filename)
-
- Outputs the result to the file named in C<$filename>.
-
- =item output_encoding()
-
- Returns the output encoding of the results. Defaults to "UTF-8".
-
- =item media_type()
-
- Returns the output media_type of the results. Defaults to "text/html".
-
- =back
-
- =head1 Parameters
-
- LibXSLT expects parameters in XPath format. That is, if you wish to pass
- a string to the XSLT engine, you actually have to pass it as a quoted
- string:
-
- $stylesheet->transform($doc, param => "'string'");
-
- Note the quotes within quotes there!
-
- Obviously this isn't much fun, so you can make it easy on yourself:
-
- $stylesheet->transform($doc, XML::LibXSLT::xpath_to_string(
- param => "string"
- ));
-
- The utility function does the right thing with respect to strings in XPath,
- including when you have quotes already embedded within your string.
-
-
- =head1 XML::LibXSLT::Security
-
- Provides an interface to the libxslt security framework by allowing callbacks
- to be defined that can restrict access to various resources (files or URLs)
- during a transformation.
-
- The libxslt security framework allows callbacks to be defined for certain
- actions that a stylesheet may attempt during a transformation. It may be
- desirable to restrict some of these actions (for example, writing a new file
- using exsl:document). The actions that may be restricted are:
-
- =over
-
- =item read_file
-
- Called when the stylesheet attempts to open a local file (ie: when using the
- document() function).
-
- =item write_file
-
- Called when an attempt is made to write a local file (ie: when using the
- exsl:document element).
-
- =item create_dir
-
- Called when a directory needs to be created in order to write a file.
-
- NOTE: By default, create_dir is not allowed. To enable it a callback must be
- registered.
-
- =item read_net
-
- Called when the stylesheet attempts to read from the network.
-
- =item write_net
-
- Called when the stylesheet attempts to write to the network.
-
- =back
-
- =head2 Using XML::LibXSLT::Security
-
- The interface for this module is similar to XML::LibXML::InputCallback. After
- creating a new instance you may register callbacks for each of the security
- options listed above. Then you apply the security preferences to the
- XML::LibXSLT or XML::LibXSLT::Stylesheet object using C<security_callbacks()>.
-
- my $security = XML::LibXSLT::Security->new();
- $security->register_callback( read_file => $read_cb );
- $security->register_callback( write_file => $write_cb );
- $security->register_callback( create_dir => $create_cb );
- $security->register_callback( read_net => $read_net_cb );
- $security->register_callback( write_net => $write_net_cb );
-
- $xslt->security_callbacks( $security );
- -OR-
- $stylesheet->security_callbacks( $security );
-
-
- The registered callback functions are called when access to a resource is
- requested. If the access should be allowed the callback should return 1, if
- not it should return 0. The callback functions should accept the following
- arguments:
-
- =over
-
- =item $tctxt
-
- This is the transform context (XML::LibXSLT::TransformContext). You can use
- this to get the current XML::LibXSLT::Stylesheet object by calling
- C<stylesheet()>.
-
- my $stylesheet = $tctxt->stylesheet();
-
- The stylesheet object can then be used to share contextual information between
- different calls to the security callbacks.
-
- =item $value
-
- This is the name of the resource (file or URI) that has been requested.
-
- =back
-
- If a particular option (except for C<create_dir>) doesn't have a registered
- callback, then the stylesheet will have full access for that action.
-
- =head2 Interface
-
- =over
-
- =item new()
-
- Creates a new XML::LibXSLT::Security object.
-
- =item register_callback( $option, $callback )
-
- Registers a callback function for the given security option (listed above).
-
- =item unregister_callback( $option )
-
- Removes the callback for the given option. This has the effect of allowing all
- access for the given option (except for C<create_dir>).
-
- =back
-
- =head1 BENCHMARK
-
- Included in the distribution is a simple benchmark script, which has two
- drivers - one for LibXSLT and one for Sablotron. The benchmark requires
- the testcases files from the XSLTMark distribution which you can find
- at http://www.datapower.com/XSLTMark/
-
- Put the testcases directory in the directory created by this distribution,
- and then run:
-
- perl benchmark.pl -h
-
- to get a list of options.
-
- The benchmark requires XML::XPath at the moment, but I hope to factor that
- out of the equation fairly soon. It also requires Time::HiRes, which I
- could be persuaded to factor out, replacing it with Benchmark.pm, but I
- haven't done so yet.
-
- I would love to get drivers for XML::XSLT and XML::Transformiix, if you
- would like to contribute them. Also if you get this running on Win32, I'd
- love to get a driver for MSXSLT via OLE, to see what we can do against
- those Redmond boys!
-
- =head1 LIBRARY VERSIONS
-
- For debugging purposes, XML::LibXSLT provides version information
- about the libxslt C library (but do not confuse it with the version
- number of XML::LibXSLT module itself, i.e. with
- C<$XML::LibXSLT::VERSION>). XML::LibXSLT issues a warning if the
- runtime version of the library is less then the compile-time version.
-
- =over
-
- =item XML::LibXSLT::LIBXSLT_VERSION()
-
- Returns version number of libxslt library which was used to compile
- XML::LibXSLT as an integer. For example, for libxslt-1.1.18, it will
- return 10118.
-
- =item XML::LibXSLT::LIBXSLT_DOTTED_VERSION()
-
- Returns version number of libxslt library which was used to compile
- XML::LibXSLT as a string, e.g. "1.1.18".
-
- =item XML::LibXSLT::LIBXSLT_RUNTIME_VERSION()
-
- Returns version number of libxslt library to which XML::LibXSLT is
- linked at runtime (either dynamically or statically). For example, for
- example, for libxslt.so.1.1.18, it will return 10118.
-
- =item XML::LibXSLT::HAVE_EXLT()
-
- Returns 1 if the module was compiled with libexslt, 0 otherwised.
-
- =back
-
- =head1 LICENSE
-
- This is free software, you may use it and distribute it under the same terms as
- Perl itself.
-
- Copyright 2001-2009, AxKit.com Ltd.
-
- =head1 AUTHOR
-
- Matt Sergeant, matt@sergeant.org
-
- Security callbacks implementation contributed by Shane Corgatelli.
-
- =head1 MAINTAINER
-
- Petr Pajas , pajas@matfyz.org
-
- =head1 BUGS
-
- Please report bugs via
-
- http://rt.cpan.org/NoAuth/Bugs.html?Dist=XML-LibXSLT
-
- =head1 SEE ALSO
-
- XML::LibXML
-
- =cut
-